package com.qianfeng.smartdevices.controller.advice;


//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼            BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  


import com.fasterxml.jackson.databind.ObjectMapper;
import com.qianfeng.smartdevices.annotations.AopLogAnnotation;
import com.qianfeng.smartdevices.dto.R;
import com.qianfeng.smartdevices.dto.ResultCode;
import com.qianfeng.smartdevices.exceptions.MybaseException;
import com.qianfeng.smartdevices.pojo.BaseUser;
import com.qianfeng.smartdevices.pojo.LogData;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by jackiechan on 2021/10/11 15:18
 *
 * @author jackiechan
 * @version 1.0
 * @since 1.0
 */
@ControllerAdvice
@ResponseBody
@Aspect
public class MyConrtrollerAdvice {

    private ObjectMapper objectMapper;

    @Autowired
    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @ExceptionHandler(MybaseException.class)
    public R processMyBaseException(MybaseException exception) {
        String message = exception.getMessage();
        int code = exception.getCode();
        return R.SetError(null, message, code);
    }

    /**
     * 处理未知异常的
     * @param exception
     * @return
     */
    @ExceptionHandler(Exception.class)
    public R processMyBaseException(Exception exception) {
        exception.printStackTrace();
        return R.SetError(null, "请检查网络", ResultCode.ERROR);
    }

    @Pointcut("execution(* com.qianfeng.smartdevices.controller.*.*(..))")
    public void qierudian() {

    }

//    @Before("qierudian()")
//    public Object proccesBefore(JoinPoint joinPoint) {
//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        System.err.println(requestAttributes);
//        HttpServletRequest servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
//        //拿到了 request 也没办法,只能获取一个请求地址,因为不同的请求不同的业务会用不同的方式传递不同的参数,不能直接获取
//        String requestURI = servletRequest.getRequestURI();
//        System.err.println(requestURI);
//        return null;
//    }

    @Around("qierudian()")
    public Object processArtound(ProceedingJoinPoint joinPoint) throws Throwable {
        //我们的日志获取用户传递的参数和处理的结果,最终合并出一次日志
        try {
            //获取参数,和方法的参数的顺序保持了一致,但是只有值,没有名字
            LogData logData = new LogData();
            Map parmaMap = new HashMap();
            Object[] args = joinPoint.getArgs();
          //  System.err.println("args:====>"+Arrays.toString(args));
            //想办法获取到方法的参数的名字
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
           // System.err.println(Arrays.toString(signature.getParameterNames()));
            String[] parameterNames = signature.getParameterNames();
            if (parameterNames != null) {
                for (int i = 0; i < parameterNames.length; i++) {
                    String parameterName = parameterNames[i];//获取每个参数名
                    Object arg = args[i];//获取到对应的参数值
                    parmaMap.put(parameterName, arg);//保存到 map 中
                }
            }
            String parmaJson = objectMapper.writeValueAsString(parmaMap);
            logData.setParmas(parmaJson);//设置参数
            //获取到这是谁
            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            if (principal != null) {
                String username = ((BaseUser) principal).getUsername();//知道是谁了
                logData.setUser(username);
            }
            Object proceed = joinPoint.proceed();//执行原始操作,并获取到结果
            if (proceed instanceof R) {
                Object result = ((R) proceed).getResult();//真正的结果
                logData.setResult(objectMapper.writeValueAsString(result));//设置结果
                logData.setMsg(((R) proceed).getMsg());
                logData.setCode(((R) proceed).getCode());
            }
            // 我们已经知道当前是谁在做操作,并且获取到了参数和返回结果,就差获取到正在干什么
            //我们的正在干什么在方法上面通过一个@AopLogAnnotation注解来说明,我们只需要获取这个注解的值就行了
            Method method = signature.getMethod();//获取到当前正在处理请求的方法
            AopLogAnnotation aopLogAnnotation = method.getAnnotation(AopLogAnnotation.class);//获取方法上的指定的注解
            if (aopLogAnnotation != null) {
                String caozuo = aopLogAnnotation.value();//获取到正在执行的操作的名字
                logData.setCaozuo(caozuo);
            }
            System.err.println("这是收集到的数据:"+logData);
            return proceed;
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        }
    }


}
